﻿using HalconDotNet;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Station.Inspect.SuaModel
{
    public struct PointL
    {
        public PointL(float x=0,float y=0,float angle=0)
        {
            X = x;Y = y;Angle = angle;
        }
        public float X { get; set; }
        public float Y { get; set; }
        public float Angle { get; set; }
    }

    public class ModelHNcc
    {
        HTuple hv_ModelID = null;

        public bool IsLoaded { get => hv_ModelID != null; }
        public static HObject BmpToHob_Color(Bitmap bmp)
        {
            try
            {
                //Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
                //BitmapData srcBmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);
                //HOperatorSet.GenImageInterleaved(out HObject image, srcBmpData.Scan0, "bgr", bmp.Width, bmp.Height, 0, "byte", 0, 0, 0, 0, -1, 0);
                //bmp.UnlockBits(srcBmpData);
                //return image;
                HObject image;
                Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
                BitmapData srcBmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

                byte[] r = new byte[srcBmpData.Height * srcBmpData.Width];
                byte[] g = new byte[srcBmpData.Height * srcBmpData.Width];
                byte[] b = new byte[srcBmpData.Height * srcBmpData.Width];

                IntPtr ptr1 = Marshal.UnsafeAddrOfPinnedArrayElement(r, 0);
                IntPtr ptr2 = Marshal.UnsafeAddrOfPinnedArrayElement(g, 0);
                IntPtr ptr3 = Marshal.UnsafeAddrOfPinnedArrayElement(b, 0);

                unsafe
                {
                    byte* pIn = (byte*)(srcBmpData.Scan0.ToPointer());
                    for (int y = 0; y < srcBmpData.Height; y++)  //列扫描
                    {
                        for (int x = 0; x < srcBmpData.Width; x++)   //行扫描
                        {
                            int index = y * srcBmpData.Width + x;
                            r[index] = pIn[0];
                            g[index] = pIn[1];
                            b[index] = pIn[2];
                            pIn += 3;
                        }
                        pIn += srcBmpData.Stride - srcBmpData.Width * 3;
                    }
                }
                HOperatorSet.GenImage3(out image, "byte", srcBmpData.Width, srcBmpData.Height, new HTuple(ptr3), new HTuple(ptr2), new HTuple(ptr1));
                bmp.UnlockBits(srcBmpData);
                return image;
            }
            catch (Exception)
            {
                return null;
            }
        }

        public void Clear()
        {
            hv_ModelID = null;
        }
        public void Load(string fileName)
        {
            Clear();
            try
            {
                HObject ho_Image, ho_GrayImage;
                HOperatorSet.GenEmptyObj(out ho_Image);
                ho_Image.Dispose();
                HOperatorSet.GenEmptyObj(out ho_GrayImage);
                ho_GrayImage.Dispose();

                HOperatorSet.ReadImage(out ho_Image, fileName);
                hv_ModelID = new HTuple();
                hv_ModelID.Dispose();
                HOperatorSet.Rgb1ToGray(ho_Image, out ho_GrayImage);
                HOperatorSet.CreateNccModel(ho_GrayImage, "auto", -0.1745, 0.349, "auto", "use_polarity", out hv_ModelID);
                ho_Image.Dispose();
                ho_GrayImage.Dispose();
            }
            catch(Exception ex)
            {
                hv_ModelID = null;
                MessageBox.Show($"模型创建失败，{ex.Message},{fileName}");
            }
        }
        public void Load(Bitmap img)
        {
            Clear();
            try
            {
                HObject ho_Image, ho_GrayImage;
                HOperatorSet.GenEmptyObj(out ho_Image);
                ho_Image.Dispose();
                HOperatorSet.GenEmptyObj(out ho_GrayImage);
                ho_GrayImage.Dispose();
                ho_Image = BmpToHob_Color(img);
                //HOperatorSet.ReadImage(out ho_Image, fileName);
                hv_ModelID = new HTuple();
                hv_ModelID.Dispose();
                HOperatorSet.Rgb1ToGray(ho_Image, out ho_GrayImage);
                HOperatorSet.CreateNccModel(ho_GrayImage, "auto", -0.1745, 0.349, "auto", "use_polarity", out hv_ModelID);
                ho_Image.Dispose();
                ho_GrayImage.Dispose();
            }
            catch (Exception ex)
            {
                hv_ModelID = null;
                MessageBox.Show($"模型创建失败，{ex.Message}");
            }
        }
        public bool Find(Bitmap img,out PointF pt,out double angle)
        {
            pt = new PointF();
            angle = 0;
            try
            {
                if (hv_ModelID == null)
                    return false;
                HObject ho_Image = BmpToHob_Color(img);
                if (ho_Image == null)
                    return false;
                //HOperatorSet.WriteImage(ho_Image, "png", 0, "D:\\12.png");
                HTuple hv_Row, hv_Column, hv_Angle, hv_Score;
                HObject ho_GrayImage;
                HOperatorSet.GenEmptyObj(out ho_GrayImage);
                ho_GrayImage.Dispose();
                HOperatorSet.Rgb1ToGray(ho_Image, out ho_GrayImage);
                HOperatorSet.FindNccModel(ho_GrayImage, hv_ModelID, -0.1745, 0.349, 0.5,1,0.95,"true",5, out hv_Row, out hv_Column,out hv_Angle,out hv_Score);
                if (hv_Score.Length == 0)
                    return false;
                pt.X = (float)(hv_Column.D - img.Width / 2);
                pt.Y = (float)(hv_Row.D - img.Height / 2);
                angle = hv_Angle.D;
                return true;
            }
            catch(Exception ex)
            {
                return false;
            }
        }

        public List<PointL> Find(Bitmap img,double threshold=0.5,int num=1)
        {
            var lst = new List<PointL>();
            try
            {
                if (hv_ModelID == null)
                    return lst;
                HObject ho_Image = BmpToHob_Color(img);
                if (ho_Image == null)
                    return lst;
                //HOperatorSet.WriteImage(ho_Image, "png", 0, "D:\\12.png");
                HTuple hv_Row, hv_Column, hv_Angle, hv_Score;
                HObject ho_GrayImage;
                HOperatorSet.GenEmptyObj(out ho_GrayImage);
                ho_GrayImage.Dispose();
                HOperatorSet.Rgb1ToGray(ho_Image, out ho_GrayImage);
                HOperatorSet.FindNccModel(ho_GrayImage, hv_ModelID, -0.1745, 0.349, threshold, num, 0.95, "true", 5, out hv_Row, out hv_Column, out hv_Angle, out hv_Score);
                if(hv_Angle.Length>0)
                {
                    var cols = hv_Column.DArr;
                    var rows = hv_Row.DArr;
                    var angles = hv_Angle.DArr;
                    for(int i=0;i<angles.Length;i++)
                    {
                        lst.Add(new PointL((float)(cols[i] - img.Width / 2), (float)(rows[i] - img.Height / 2), (float)angles[i]));
                    }
                }
            }
            catch (Exception ex)
            {
            }
            return lst;
        }
    }
}
